package com.my.zl.console.common.config.mybatis;

import java.lang.reflect.Field;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.resultset.DefaultResultSetHandler;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.mapping.ResultSetType;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.type.BlobTypeHandler;
import org.apache.ibatis.type.ClobTypeHandler;
import org.apache.ibatis.type.DateTypeHandler;
import org.apache.ibatis.type.InstantTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ReflectionUtils;

import com.my.zl.console.common.aop.LogManagerFilter;

@Intercepts(@Signature(method = "handleResultSets", type = ResultSetHandler.class, args = {Statement.class}))
public class MapInterceptor implements Interceptor {
    // 日志
    private static Logger LOGGER = LoggerFactory.getLogger(LogManagerFilter.class);
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 获取代理目标对象
        Object target = invocation.getTarget();
        if (target instanceof DefaultResultSetHandler) {
            
            // 获取当前statement
            Statement stmt = (Statement) invocation.getArgs()[0];
            
            ResultSet resultSet = stmt.getResultSet();
            
            List<Object> resultList = new ArrayList<Object>();
            boolean flag = false;
            try {
                //获取节点属性的集合
                DefaultResultSetHandler defaultResultSetHandler = (DefaultResultSetHandler) invocation.getTarget();
                // 利用反射获取参数对象
//              ParameterHandler parameterHandler = reflect(defaultResultSetHandler);
//              Object parameterObj = parameterHandler.getParameterObject();
                
                MetaObject metaStatementHandler = SystemMetaObject.forObject(defaultResultSetHandler);
                MappedStatement mappedStatement = (MappedStatement) metaStatementHandler.getValue("mappedStatement");
                List<ResultMap> resultMaps = mappedStatement.getResultMaps();
                
                if(resultMaps != null && resultMaps.size()>0){
                    Class<?> resultType = resultMaps.get(0).getType();
                    if(resultType.getSimpleName().equals("MapString")){
                        flag = true;
                        LOGGER.info("MapString转换类型");
                        //获得对应列名
                        ResultSetMetaData rsmd = resultSet.getMetaData();
                        
                        List<String> columnList = new ArrayList<>();
                        List<Integer> columnTypes = new ArrayList<>();
                        for (int i = 1; i <= rsmd.getColumnCount(); i++) {
                            columnList.add(rsmd.getColumnName(i));
                            columnTypes.add(rsmd.getColumnType(i));
                        }
                        
                        while (resultSet.next()) {
                            MapString<String, Object> resultMap = new MapString<String, Object>();
                            for (int i=0,ln=columnList.size(); i<ln; i++) {
//                                LOGGER.info("MapString转换类型>>{}", columnList.get(i) +"-"+ columnTypes.get(i));
                                resultMap.put(columnList.get(i), typeCovertToString(resultSet,columnList.get(i),columnTypes.get(i)));
                            }
                            resultList.add(resultMap);
                        }
                        return resultList;
                    }
                }
            } catch (SQLException e) {
                LOGGER.error("map interceptor异常>>{}", e.getMessage());
            } catch (Exception e) {
                LOGGER.error("map interceptor异常>>{}", e.getMessage());
            } finally {
                if(flag){
                    // 关闭result set
                    closeResultSet(resultSet);
                }
            }
        }
        return invocation.proceed();
    }
    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }
    @Override
    public void setProperties(Properties properties) {
    }

    private void closeResultSet(ResultSet resultSet) {
        try {
            if (resultSet != null) {
                resultSet.close();
            }
        } catch (SQLException e) {
            LOGGER.error("关闭 result set异常,{}", e.getMessage());
        }
    }

    private ParameterHandler reflect(DefaultResultSetHandler resultSetHandler) {
        Field field = ReflectionUtils.findField(DefaultResultSetHandler.class,"parameterHandler");
        field.setAccessible(true);
        Object value = null;
        try {
            value = field.get(resultSetHandler);
        } catch (Exception e) {
            LOGGER.error("默认返回结果集反射参数对象异常，{}", e.getMessage());
        }
        return (ParameterHandler) value;
    }

    private String typeCovertToString(ResultSet resultSet,String columnLabel,Integer type) {
        String val = " ";
        
        try{
            Object value = resultSet.getObject(columnLabel);
            if(value==null){
                return val;
            }
            switch(JdbcType.forCode(type))
            {
                case CLOB:
                    val = new ClobTypeHandler().getNullableResult(resultSet, columnLabel);
                    break;
                case TIMESTAMP: 
                    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneId.systemDefault());
                    val = formatter.format(new InstantTypeHandler().getNullableResult(resultSet, columnLabel));
                    break;
                case DATE: 
                    DateFormat ddf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    val = ddf.format(new DateTypeHandler().getNullableResult(resultSet, columnLabel));
                    break;
                case BLOB:
                    val = new String(new BlobTypeHandler().getNullableResult(resultSet, columnLabel),"UTF-8");
                    break;
                default:
                    val = value.toString();
            }
        }catch (Exception e) {
            LOGGER.error("类型转换异常>>{},{}",columnLabel, e);
        }
        return val;
    }
}